#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
HTTP明文传输检测工具
版本: 2.0
功能: 检测网站是否使用HTTP明文传输协议并进行安全分析（增强证据展示）
作者: 来自于狂人（CSDN博客同名）
"""

import requests
import urllib3
import socket
import ssl
from urllib.parse import urlparse
import time
import sys
import re
from datetime import datetime
import json
import os

# 禁用SSL证书验证警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class HTTPProtocolDetector:
    def __init__(self, target_url, timeout=10):
        """
        初始化检测器
        :param target_url: 目标URL
        :param timeout: 超时时间
        """
        self.target_url = target_url
        self.timeout = timeout
        self.parsed_url = urlparse(target_url)
        self.host = self.parsed_url.hostname
        self.port = self.parsed_url.port or (443 if self.parsed_url.scheme == 'https' else 80)
        self.scheme = self.parsed_url.scheme
        self.results = {
            'target_url': target_url,
            'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
            'protocol_analysis': {},
            'security_headers': {},
            'redirect_analysis': {},
            'ssl_analysis': {},
            'evidence': [],  # 新增：存储检测证据
            'recommendations': []
        }

    def add_evidence(self, category, level, message, details=None):
        """
        添加检测证据
        :param category: 证据类别（如：HTTP访问、重定向、SSL等）
        :param level: 严重程度（info/warning/critical）
        :param message: 证据描述
        :param details: 详细信息（可选）
        """
        evidence = {
            'timestamp': datetime.now().strftime('%H:%M:%S'),
            'category': category,
            'level': level,
            'message': message
        }
        if details:
            evidence['details'] = details
        
        self.results['evidence'].append(evidence)
        
        # 实时打印证据
        level_symbols = {
            'info': '[+]',
            'warning': '[!]',
            'critical': '[X]'
        }
        print(f"    {level_symbols.get(level, '[-]')} {message}")
        if details:
            for key, value in details.items():
                print(f"        - {key}: {value}")

    def check_http_accessibility(self):
        """检查HTTP协议可访问性（增强版）"""
        print(f"\n[检测维度1: HTTP协议可访问性]")
        print("-" * 60)
        
        # 尝试直接访问HTTP
        http_url = f"http://{self.host}" + (f":{self.port}" if self.port != 80 else "")
        print(f"    尝试访问: {http_url}")
        
        try:
            start_time = time.time()
            response = requests.get(http_url, timeout=self.timeout, verify=False, allow_redirects=False)
            elapsed_time = time.time() - start_time
            
            result = {
                'accessible': True,
                'status_code': response.status_code,
                'response_time': elapsed_time,
                'content_length': len(response.content),
                'headers': dict(response.headers)
            }
            
            # 添加证据
            self.add_evidence(
                category="HTTP访问",
                level="critical" if response.status_code == 200 else "warning",
                message=f"HTTP协议可访问 - 存在明文传输风险",
                details={
                    "URL": http_url,
                    "状态码": response.status_code,
                    "响应时间": f"{elapsed_time:.3f}秒",
                    "内容长度": f"{len(response.content)} 字节",
                    "服务器": response.headers.get('Server', '未知')
                }
            )
            
            # 检查响应内容特征
            if response.status_code == 200:
                content_preview = response.text[:200].replace('\n', ' ')
                self.add_evidence(
                    category="HTTP访问",
                    level="critical",
                    message="HTTP返回完整页面内容",
                    details={
                        "内容预览": content_preview + "...",
                        "Content-Type": response.headers.get('Content-Type', '未知')
                    }
                )
            
            return result
            
        except requests.exceptions.Timeout:
            self.add_evidence(
                category="HTTP访问",
                level="info",
                message="HTTP访问超时",
                details={"URL": http_url, "超时时间": f"{self.timeout}秒"}
            )
            return {'accessible': False, 'error': '连接超时'}
            
        except requests.exceptions.ConnectionError as e:
            self.add_evidence(
                category="HTTP访问",
                level="info",
                message="HTTP无法连接（可能已禁用）",
                details={"URL": http_url, "错误": str(e)[:100]}
            )
            return {'accessible': False, 'error': '连接失败'}
            
        except Exception as e:
            self.add_evidence(
                category="HTTP访问",
                level="warning",
                message=f"HTTP访问异常",
                details={"错误": str(e)}
            )
            return {'accessible': False, 'error': str(e)}

    def check_https_accessibility(self):
        """检查HTTPS协议可访问性（增强版）"""
        print(f"\n[检测维度2: HTTPS协议可访问性]")
        print("-" * 60)
        
        # 尝试直接访问HTTPS
        https_url = f"https://{self.host}" + (f":{self.port}" if self.port != 443 else "")
        print(f"    尝试访问: {https_url}")
        
        try:
            start_time = time.time()
            response = requests.get(https_url, timeout=self.timeout, verify=False, allow_redirects=False)
            elapsed_time = time.time() - start_time
            
            result = {
                'accessible': True,
                'status_code': response.status_code,
                'response_time': elapsed_time,
                'content_length': len(response.content),
                'headers': dict(response.headers)
            }
            
            # 添加证据
            self.add_evidence(
                category="HTTPS访问",
                level="info",
                message="HTTPS协议可访问",
                details={
                    "URL": https_url,
                    "状态码": response.status_code,
                    "响应时间": f"{elapsed_time:.3f}秒",
                    "内容长度": f"{len(response.content)} 字节",
                    "TLS版本": response.raw.version if hasattr(response.raw, 'version') else "未知"
                }
            )
            
            return result
            
        except requests.exceptions.SSLError as e:
            self.add_evidence(
                category="HTTPS访问",
                level="warning",
                message="HTTPS SSL证书验证失败",
                details={"错误": str(e)[:200]}
            )
            return {'accessible': False, 'error': 'SSL错误'}
            
        except Exception as e:
            self.add_evidence(
                category="HTTPS访问",
                level="warning",
                message="HTTPS访问失败",
                details={"错误": str(e)}
            )
            return {'accessible': False, 'error': str(e)}

    def check_protocol_redirects(self):
        """检查协议重定向配置（增强版）"""
        print(f"\n[检测维度3: 协议重定向配置]")
        print("-" * 60)
        
        # 检查HTTP到HTTPS重定向
        http_url = f"http://{self.host}" + (f":{self.port}" if self.port != 80 else "")
        print(f"    检测重定向: {http_url}")
        
        try:
            response = requests.get(http_url, timeout=self.timeout, allow_redirects=True, verify=False)
            
            redirect_info = {
                'has_redirect': len(response.history) > 0,
                'redirect_chain': [],
                'final_url': response.url,
                'status_codes': [r.status_code for r in response.history] + [response.status_code]
            }
            
            if len(response.history) > 0:
                # 有重定向
                for i, resp in enumerate(response.history, 1):
                    location = resp.headers.get('Location', '')
                    redirect_info['redirect_chain'].append({
                        'from': resp.url,
                        'to': location,
                        'status': resp.status_code
                    })
                    
                    # 添加重定向证据
                    is_https_redirect = location.startswith('https://')
                    self.add_evidence(
                        category="重定向",
                        level="info" if is_https_redirect else "warning",
                        message=f"第{i}步重定向: {resp.status_code}",
                        details={
                            "源地址": resp.url,
                            "目标地址": location,
                            "状态码": resp.status_code,
                            "重定向类型": "永久重定向(301)" if resp.status_code == 301 else "临时重定向(302)" if resp.status_code == 302 else f"其他({resp.status_code})"
                        }
                    )
                
                # 检查最终URL
                final_is_https = response.url.startswith('https://')
                self.add_evidence(
                    category="重定向",
                    level="info" if final_is_https else "critical",
                    message=f"最终URL: {response.url}",
                    details={
                        "协议": "HTTPS" if final_is_https else "HTTP",
                        "重定向步数": len(response.history),
                        "最终状态码": response.status_code
                    }
                )
                
            else:
                # 无重定向
                self.add_evidence(
                    category="重定向",
                    level="critical",
                    message="HTTP未配置重定向到HTTPS",
                    details={
                        "URL": http_url,
                        "状态码": response.status_code,
                        "风险": "用户可能通过HTTP明文访问网站"
                    }
                )
            
            return redirect_info
            
        except Exception as e:
            self.add_evidence(
                category="重定向",
                level="warning",
                message="重定向检测失败",
                details={"错误": str(e)}
            )
            return {'has_redirect': False, 'error': str(e)}

    def check_ssl_certificate(self):
        """检查SSL证书信息（增强版）"""
        print(f"\n[检测维度4: SSL证书信息]")
        print("-" * 60)
        
        if self.parsed_url.scheme != 'https':
            self.add_evidence(
                category="SSL证书",
                level="info",
                message="目标不是HTTPS协议，跳过SSL检测"
            )
            return {'ssl_available': False, 'message': '目标不是HTTPS协议'}
        
        try:
            # 获取SSL证书信息
            context = ssl.create_default_context()
            context.check_hostname = False
            context.verify_mode = ssl.CERT_NONE
            
            print(f"    连接到: {self.host}:443")
            
            with socket.create_connection((self.host, 443), timeout=self.timeout) as sock:
                with context.wrap_socket(sock, server_hostname=self.host) as ssock:
                    cert = ssock.getpeercert()
                    cipher = ssock.cipher()
                    
                    # 提取证书信息
                    cert_info = {
                        'ssl_available': True,
                        'subject': dict(x[0] for x in cert['subject']),
                        'issuer': dict(x[0] for x in cert['issuer']),
                        'version': cert.get('version'),
                        'serial_number': cert.get('serialNumber'),
                        'not_before': cert.get('notBefore'),
                        'not_after': cert.get('notAfter'),
                        'signature_algorithm': cert.get('signatureAlgorithm'),
                        'alt_names': [x[1] for x in cert.get('subjectAltName', [])],
                        'cipher': cipher
                    }
                    
                    # 添加SSL证书证据
                    self.add_evidence(
                        category="SSL证书",
                        level="info",
                        message="SSL证书信息获取成功",
                        details={
                            "证书颁发者": cert_info['issuer'].get('commonName', '未知'),
                            "证书主题": cert_info['subject'].get('commonName', '未知'),
                            "有效期开始": cert_info['not_before'],
                            "有效期结束": cert_info['not_after'],
                            "加密套件": f"{cipher[0]} ({cipher[1]})" if cipher else "未知"
                        }
                    )
                    
                    # 检查证书有效期
                    try:
                        from dateutil import parser
                        import pytz
                        
                        not_after = parser.parse(cert['notAfter'])
                        now = datetime.now(pytz.utc)
                        
                        if now > not_after:
                            cert_info['expired'] = True
                            self.add_evidence(
                                category="SSL证书",
                                level="critical",
                                message="SSL证书已过期",
                                details={
                                    "过期时间": cert_info['not_after'],
                                    "当前时间": now.strftime('%Y-%m-%d %H:%M:%S %Z')
                                }
                            )
                        else:
                            days_left = (not_after - now).days
                            cert_info['expired'] = False
                            cert_info['days_until_expiration'] = days_left
                            
                            level = "warning" if days_left < 30 else "info"
                            self.add_evidence(
                                category="SSL证书",
                                level=level,
                                message=f"SSL证书有效（剩余{days_left}天）",
                                details={
                                    "到期时间": cert_info['not_after'],
                                    "剩余天数": days_left
                                }
                            )
                    except ImportError:
                        self.add_evidence(
                            category="SSL证书",
                            level="warning",
                            message="无法检查证书有效期（缺少dateutil库）"
                        )
                    
                    # 检查证书域名匹配
                    alt_names = cert_info['alt_names']
                    if alt_names:
                        self.add_evidence(
                            category="SSL证书",
                            level="info",
                            message=f"证书支持{len(alt_names)}个域名",
                            details={
                                "支持的域名": ", ".join(alt_names[:5]) + ("..." if len(alt_names) > 5 else "")
                            }
                        )
                    
                    return cert_info
                    
        except socket.timeout:
            self.add_evidence(
                category="SSL证书",
                level="warning",
                message="SSL连接超时",
                details={"主机": self.host, "端口": 443}
            )
            return {'ssl_available': False, 'error': '连接超时'}
            
        except ssl.SSLError as e:
            self.add_evidence(
                category="SSL证书",
                level="critical",
                message="SSL证书验证失败",
                details={"错误": str(e)}
            )
            return {'ssl_available': False, 'error': str(e)}
            
        except Exception as e:
            self.add_evidence(
                category="SSL证书",
                level="warning",
                message="SSL证书检测异常",
                details={"错误": str(e)}
            )
            return {'ssl_available': False, 'error': str(e)}

    def check_security_headers(self):
        """检查安全头信息（增强版）"""
        print(f"\n[检测维度5: 安全头配置]")
        print("-" * 60)
        
        try:
            # 首先尝试HTTPS
            url = f"https://{self.host}" + (f":{self.port}" if self.port != 443 else "")
            protocol_used = "HTTPS"
            
            try:
                response = requests.get(url, timeout=self.timeout, verify=False)
            except:
                # 如果HTTPS失败，尝试HTTP
                url = f"http://{self.host}" + (f":{self.port}" if self.port != 80 else "")
                protocol_used = "HTTP"
                response = requests.get(url, timeout=self.timeout, verify=False)
            
            print(f"    通过{protocol_used}检测安全头")
            
            headers = response.headers
            
            security_headers = {
                'hsts': headers.get('Strict-Transport-Security', 'Not Set'),
                'content_security_policy': headers.get('Content-Security-Policy', 'Not Set'),
                'x_frame_options': headers.get('X-Frame-Options', 'Not Set'),
                'x_content_type_options': headers.get('X-Content-Type-Options', 'Not Set'),
                'x_xss_protection': headers.get('X-XSS-Protection', 'Not Set'),
                'referrer_policy': headers.get('Referrer-Policy', 'Not Set'),
                'permissions_policy': headers.get('Permissions-Policy', 'Not Set')
            }
            
            # 检查HSTS
            if security_headers['hsts'] != 'Not Set':
                self.add_evidence(
                    category="安全头",
                    level="info",
                    message="HSTS已配置",
                    details={
                        "值": security_headers['hsts'],
                        "作用": "强制浏览器使用HTTPS访问"
                    }
                )
            else:
                self.add_evidence(
                    category="安全头",
                    level="warning",
                    message="HSTS未配置",
                    details={
                        "风险": "浏览器可能首次使用HTTP访问",
                        "建议": "添加 Strict-Transport-Security 头"
                    }
                )
            
            # 检查CSP
            if security_headers['content_security_policy'] != 'Not Set':
                self.add_evidence(
                    category="安全头",
                    level="info",
                    message="CSP已配置",
                    details={
                        "值": security_headers['content_security_policy'][:100] + "..."
                    }
                )
            else:
                self.add_evidence(
                    category="安全头",
                    level="warning",
                    message="CSP未配置",
                    details={
                        "风险": "可能遭受XSS攻击",
                        "建议": "添加 Content-Security-Policy 头"
                    }
                )
            
            # 检查X-Frame-Options
            if security_headers['x_frame_options'] != 'Not Set':
                self.add_evidence(
                    category="安全头",
                    level="info",
                    message="X-Frame-Options已配置",
                    details={
                        "值": security_headers['x_frame_options'],
                        "作用": "防止点击劫持攻击"
                    }
                )
            else:
                self.add_evidence(
                    category="安全头",
                    level="warning",
                    message="X-Frame-Options未配置",
                    details={
                        "风险": "可能遭受点击劫持攻击",
                        "建议": "添加 X-Frame-Options: DENY 或 SAMEORIGIN"
                    }
                )
            
            # 检查X-Content-Type-Options
            if security_headers['x_content_type_options'] != 'Not Set':
                self.add_evidence(
                    category="安全头",
                    level="info",
                    message="X-Content-Type-Options已配置",
                    details={"值": security_headers['x_content_type_options']}
                )
            else:
                self.add_evidence(
                    category="安全头",
                    level="warning",
                    message="X-Content-Type-Options未配置",
                    details={
                        "风险": "可能遭受MIME类型嗅探攻击",
                        "建议": "添加 X-Content-Type-Options: nosniff"
                    }
                )
            
            return security_headers
            
        except Exception as e:
            self.add_evidence(
                category="安全头",
                level="warning",
                message="安全头检测失败",
                details={"错误": str(e)}
            )
            return {'error': str(e)}

    def analyze_protocol_risks(self, http_result, https_result, redirect_info):
        """分析协议风险（增强版）"""
        print(f"\n[检测维度6: 协议风险分析]")
        print("-" * 60)
        
        risks = []
        
        # 检查是否同时支持HTTP和HTTPS
        if http_result.get('accessible') and https_result.get('accessible'):
            risk = "同时支持HTTP和HTTPS协议"
            risks.append(risk)
            self.add_evidence(
                category="风险分析",
                level="warning",
                message=risk,
                details={
                    "HTTP状态": f"可访问 ({http_result['status_code']})",
                    "HTTPS状态": f"可访问 ({https_result['status_code']})",
                    "风险": "用户可能通过HTTP明文访问"
                }
            )
        
        # 检查HTTP是否可访问
        if http_result.get('accessible'):
            risk = f"HTTP协议可访问 (状态码: {http_result['status_code']})"
            risks.append(risk)
            
            if http_result['status_code'] == 200:
                self.add_evidence(
                    category="风险分析",
                    level="critical",
                    message="HTTP返回完整页面 - 严重安全风险",
                    details={
                        "状态码": http_result['status_code'],
                        "内容长度": f"{http_result['content_length']} 字节",
                        "风险": "敏感数据可能通过明文传输",
                        "影响": "账号密码、个人信息等可能被窃听"
                    }
                )
        
        # 检查是否有安全重定向
        if http_result.get('accessible') and not redirect_info.get('has_redirect'):
            risk = "HTTP未重定向到HTTPS"
            risks.append(risk)
            self.add_evidence(
                category="风险分析",
                level="critical",
                message=risk,
                details={
                    "风险": "用户可能长期使用HTTP访问",
                    "影响": "所有通信内容可被中间人窃听",
                    "建议": "配置301永久重定向到HTTPS"
                }
            )
        
        # 检查重定向类型
        if redirect_info.get('has_redirect'):
            for step in redirect_info['redirect_chain']:
                if step['status'] == 302:
                    self.add_evidence(
                        category="风险分析",
                        level="warning",
                        message="使用302临时重定向",
                        details={
                            "当前状态": "302临时重定向",
                            "建议": "改用301永久重定向",
                            "原因": "301可被浏览器缓存，减少HTTP请求"
                        }
                    )
                    break
        
        # 检查响应时间差异
        if http_result.get('response_time') and https_result.get('response_time'):
            http_time = http_result['response_time']
            https_time = https_result['response_time']
            time_diff = abs(http_time - https_time)
            
            if time_diff > 2:
                risk = f"HTTP和HTTPS响应时间差异较大 ({time_diff:.2f}秒)"
                risks.append(risk)
                self.add_evidence(
                    category="风险分析",
                    level="warning",
                    message=risk,
                    details={
                        "HTTP响应时间": f"{http_time:.3f}秒",
                        "HTTPS响应时间": f"{https_time:.3f}秒",
                        "差异": f"{time_diff:.3f}秒",
                        "可能原因": "不同的处理逻辑或服务器配置"
                    }
                )
        
        return risks

    def generate_recommendations(self, risks, security_headers):
        """生成安全建议（增强版）"""
        print(f"\n[检测维度7: 安全建议生成]")
        print("-" * 60)
        
        recommendations = []
        
        # 基于风险生成建议
        for risk in risks:
            if "明文传输风险" in risk or "HTTP协议可访问" in risk:
                rec = "【高优先级】完全禁用HTTP访问，仅允许HTTPS"
                recommendations.append(rec)
                self.add_evidence(
                    category="安全建议",
                    level="critical",
                    message=rec,
                    details={
                        "实施方法": "在Web服务器配置中关闭80端口或配置拒绝访问",
                        "参考配置": "Nginx: return 444; | Apache: Require all denied"
                    }
                )
            
            if "未重定向到HTTPS" in risk:
                rec = "【高优先级】配置HTTP到HTTPS的301永久重定向"
                recommendations.append(rec)
                self.add_evidence(
                    category="安全建议",
                    level="critical",
                    message=rec,
                    details={
                        "实施方法": "在Web服务器配置301重定向规则",
                        "Nginx配置": "return 301 https://$host$request_uri;",
                        "Apache配置": "Redirect 301 / https://yourdomain.com/"
                    }
                )
        
        # 基于安全头缺失生成建议
        if security_headers.get('hsts') == 'Not Set':
            rec = "【中优先级】启用HTTP Strict Transport Security (HSTS)"
            recommendations.append(rec)
            self.add_evidence(
                category="安全建议",
                level="warning",
                message=rec,
                details={
                    "作用": "强制浏览器始终使用HTTPS访问",
                    "配置示例": "Strict-Transport-Security: max-age=31536000; includeSubDomains",
                    "注意": "确保HTTPS完全配置好后再启用"
                }
            )
        
        if security_headers.get('content_security_policy') == 'Not Set':
            rec = "【中优先级】配置Content Security Policy (CSP)"
            recommendations.append(rec)
            self.add_evidence(
                category="安全建议",
                level="warning",
                message=rec,
                details={
                    "作用": "防止XSS攻击和数据注入",
                    "基础配置": "Content-Security-Policy: default-src 'self'"
                }
            )
        
        if security_headers.get('x_frame_options') == 'Not Set':
            rec = "【中优先级】设置X-Frame-Options头防止点击劫持"
            recommendations.append(rec)
            self.add_evidence(
                category="安全建议",
                level="warning",
                message=rec,
                details={
                    "作用": "防止网站被嵌入iframe",
                    "配置示例": "X-Frame-Options: DENY 或 SAMEORIGIN"
                }
            )
        
        # 去重
        recommendations = list(dict.fromkeys(recommendations))
        
        return recommendations

    def run_full_analysis(self):
        """运行完整分析"""
        print(f"[*] 开始分析目标: {self.target_url}")
        print("="*60)
        
        # 1. 检查HTTP可访问性
        http_result = self.check_http_accessibility()
        self.results['protocol_analysis']['http'] = http_result
        
        # 2. 检查HTTPS可访问性
        https_result = self.check_https_accessibility()
        self.results['protocol_analysis']['https'] = https_result
        
        # 3. 检查协议重定向
        redirect_info = self.check_protocol_redirects()
        self.results['redirect_analysis'] = redirect_info
        
        # 4. 检查SSL证书（如果HTTPS可用）
        if https_result.get('accessible'):
            ssl_info = self.check_ssl_certificate()
            self.results['ssl_analysis'] = ssl_info
        
        # 5. 检查安全头
        security_headers = self.check_security_headers()
        self.results['security_headers'] = security_headers
        
        # 6. 分析协议风险
        risks = self.analyze_protocol_risks(http_result, https_result, redirect_info)
        self.results['protocol_analysis']['risks'] = risks
        
        # 7. 生成安全建议
        recommendations = self.generate_recommendations(risks, security_headers)
        self.results['recommendations'] = recommendations
        
        return self.results

    def print_evidence_summary(self):
        """打印证据摘要"""
        print("\n" + "="*60)
        print("检测证据摘要")
        print("="*60)
        
        evidence_by_category = {}
        for ev in self.results['evidence']:
            category = ev['category']
            if category not in evidence_by_category:
                evidence_by_category[category] = []
            evidence_by_category[category].append(ev)
        
        for category, evidences in evidence_by_category.items():
            print(f"\n[{category}] - 共{len(evidences)}条证据")
            print("-" * 40)
            
            for i, ev in enumerate(evidences, 1):
                level_symbols = {
                    'info': '✓',
                    'warning': '⚠',
                    'critical': '✗'
                }
                symbol = level_symbols.get(ev['level'], '-')
                print(f"  {i}. [{symbol}] {ev['message']}")
                
                if ev.get('details'):
                    for key, value in ev['details'].items():
                        print(f"       {key}: {value}")

    def print_detailed_report(self):
        """打印详细报告"""
        print("\n" + "="*60)
        print("HTTP明文传输检测报告")
        print("="*60)
        print(f"目标URL: {self.results['target_url']}")
        print(f"检测时间: {self.results['timestamp']}")
        print()
        
        # 打印证据摘要
        self.print_evidence_summary()
        
        # 最终判断
        print("\n" + "="*60)
        print("最终安全评估")
        print("="*60)
        
        http_info = self.results['protocol_analysis']['http']
        https_info = self.results['protocol_analysis']['https']
        redirect_info = self.results['redirect_analysis']
        
        critical_count = sum(1 for ev in self.results['evidence'] if ev['level'] == 'critical')
        warning_count = sum(1 for ev in self.results['evidence'] if ev['level'] == 'warning')
        
        print(f"\n证据统计:")
        print(f"  - 严重问题: {critical_count} 个")
        print(f"  - 警告问题: {warning_count} 个")
        print(f"  - 总证据数: {len(self.results['evidence'])} 条")
        
        print(f"\n安全评级:")
        if http_info.get('accessible') and not redirect_info.get('has_redirect'):
            print("  ❌ 不安全 (D级)")
            print("  - HTTP可访问且未重定向")
            print("  - 存在严重的明文传输风险")
            print("  - 建议立即整改")
        elif http_info.get('accessible') and redirect_info.get('has_redirect'):
            print("  ⚠️  需改进 (C级)")
            print("  - HTTP可访问但已重定向")
            print("  - 建议完全禁用HTTP")
        elif https_info.get('accessible') and not http_info.get('accessible'):
            hsts_set = self.results['security_headers'].get('hsts') != 'Not Set'
            if hsts_set and warning_count == 0:
                print("  ✓ 安全 (A级)")
                print("  - 仅HTTPS可访问")
                print("  - HSTS已配置")
                print("  - 安全头配置完善")
            else:
                print("  ✓ 较安全 (B级)")
                print("  - 仅HTTPS可访问")
                print("  - 建议完善安全头配置")
        else:
            print("  ❓ 无法评估")
            print("  - 协议配置异常")

    def save_report(self, filename=None):
        """保存报告到文件"""
        if filename is None:
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename = f"http_protocol_analysis_{timestamp}.json"
        
        with open(filename, 'w', encoding='utf-8') as f:
            json.dump(self.results, f, indent=2, ensure_ascii=False)
        
        print(f"\n[+] 详细报告已保存至: {filename}")
        return filename

def batch_analyze(urls_file):
    """批量分析URL列表"""
    print(f"[*] 开始批量分析URL列表: {urls_file}")
    
    if not os.path.exists(urls_file):
        print(f"[!] 文件不存在: {urls_file}")
        return
    
    with open(urls_file, 'r', encoding='utf-8') as f:
        urls = [line.strip() for line in f if line.strip()]
    
    print(f"[*] 发现 {len(urls)} 个URL待分析")
    
    batch_results = []
    for i, url in enumerate(urls, 1):
        print(f"\n{'='*60}")
        print(f"[{i}/{len(urls)}] 分析: {url}")
        print('='*60)
        
        try:
            detector = HTTPProtocolDetector(url)
            result = detector.run_full_analysis()
            batch_results.append(result)
            
            # 简化输出
            http_acc = result['protocol_analysis']['http'].get('accessible', False)
            https_acc = result['protocol_analysis']['https'].get('accessible', False)
            has_redirect = result['redirect_analysis'].get('has_redirect', False)
            critical_count = sum(1 for ev in result['evidence'] if ev['level'] == 'critical')
            
            status = "安全" if https_acc and not http_acc else "需改进" if https_acc and has_redirect else "不安全"
            print(f"\n[摘要] 状态: {status} | HTTP: {'✓' if http_acc else '✗'} | HTTPS: {'✓' if https_acc else '✗'} | 重定向: {'✓' if has_redirect else '✗'} | 严重问题: {critical_count}")
            
        except Exception as e:
            print(f"[!] 错误: {str(e)}")
            batch_results.append({
                'target_url': url,
                'error': str(e),
                'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            })
    
    # 生成批量报告
    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    batch_filename = f"batch_http_analysis_{timestamp}.json"
    with open(batch_filename, 'w', encoding='utf-8') as f:
        json.dump(batch_results, f, indent=2, ensure_ascii=False)
    
    print(f"\n{'='*60}")
    print(f"[+] 批量分析完成，结果保存至: {batch_filename}")
    
    # 生成摘要
    secure_count = sum(1 for r in batch_results 
                      if r.get('protocol_analysis', {}).get('https', {}).get('accessible') 
                      and not r.get('protocol_analysis', {}).get('http', {}).get('accessible'))
    improvement_count = sum(1 for r in batch_results 
                           if r.get('protocol_analysis', {}).get('https', {}).get('accessible') 
                           and r.get('redirect_analysis', {}).get('has_redirect'))
    insecure_count = len(batch_results) - secure_count - improvement_count
    
    print(f"\n批量分析摘要:")
    print(f"  安全配置 (A/B级): {secure_count}")
    print(f"  需要改进 (C级): {improvement_count}")
    print(f"  不安全 (D级): {insecure_count}")

def main():
    """主函数"""
    print("""
    ===========================================
    |      HTTP明文传输检测工具 v2.0         |
    |        Kali Linux 专业版               |
    |    增强：详细证据展示与过程追踪        |
    ===========================================
    """)
    
    print("请选择操作模式:")
    print("1. 单个URL检测")
    print("2. 批量URL检测")
    
    choice = input("\n[?] 请选择 (1/2): ").strip()
    
    if choice == "1":
        # 单个URL检测
        target_url = input("\n[+] 请输入目标URL (例如: https://example.com): ").strip()
        
        if not target_url:
            print("[!] URL不能为空")
            return
        
        if not target_url.startswith(('http://', 'https://')):
            target_url = 'https://' + target_url
        
        try:
            detector = HTTPProtocolDetector(target_url)
            results = detector.run_full_analysis()
            detector.print_detailed_report()
            
            # 询问是否保存报告
            save_choice = input("\n[?] 是否保存详细报告? (y/n): ").lower()
            if save_choice == 'y':
                detector.save_report()
                
        except KeyboardInterrupt:
            print("\n[!] 用户中断操作")
        except Exception as e:
            print(f"[!] 检测过程中出现错误: {str(e)}")
            import traceback
            traceback.print_exc()
    
    elif choice == "2":
        # 批量检测
        urls_file = input("\n[+] 请输入包含URL列表的文件路径: ").strip()
        batch_analyze(urls_file)
    
    else:
        print("[!] 无效选择")

if __name__ == "__main__":
    main()
